#include "bsp_adc.h"
#include "apm32f0xx_gpio.h"
#include "apm32f0xx_misc.h"
#include "apm32f0xx_gpio.h"
#include "apm32f0xx_adc.h"
#include "apm32f0xx_misc.h"
#include "apm32f0xx_usart.h"
#include "apm32f0xx_dma.h"
#include "bsp_multi_adc.h"
#include <stdio.h>

//#define _DEBUG_OUT_

#ifdef _DEBUG_OUT_
    // #define LED_DEBUG_OUT(format, ...)   printf(format, ##__VA_ARGS__)
    #define DEBUG_OUT(format, ...)   printf(format, ##__VA_ARGS__)
#else
    #define DEBUG_OUT(format, ...)
#endif


//  原理图     MCU引脚
// BAT1_ADC    PA0  ADC_IN0   √  adcData[0]
// BAT2_ADC    PA1  ADC_IN1   √  adcData[1]
// USB_DET     PA3  ADC_IN3   √  adcData[2] 
// BAT3_ADC    PA4  ADC_IN4   √  adcData[3] 
// BAT4_ADC    PA5  ADC_IN5   √  adcData[4]
// BAT5_ADC    PA6  ADC_IN6   √  adcData[5]
// BAT6_ADC    PA7  ADC_IN7   √  adcData[6]
// BAT8_ADC    PB0  ADC_IN8   √  adcData[7]
// NTC         PC4  ADC_IN14  √  adcData[8]
// BAT7_ADC    PC5  ADC_IN15  √  adcData[9]



#define ADC_CH_SIZE         10
#define ADC_DR_ADDR         ((uint32_t)ADC_BASE + 0x40)

uint16_t adcData[ADC_CH_SIZE];

static void swap(uint16_t* a, uint16_t* b) 
{
    uint16_t temp = *a;
	
    *a = *b;
    *b = temp;
}

static int partition(uint16_t arr[], int low, int high) 
{
	int j;
    uint16_t pivot = arr[high];
    int i = (low - 1);
    
    for (j = low; j <= high - 1; j++) 
	{
        if (arr[j] < pivot) 
		{
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[high]);
	
    return (i + 1);
}

void quickSort(uint16_t arr[], int low, int high) 
{
	int pi;
	
    if (low < high) 
	{
        pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

/*!
 * @brief     DMA Init
 *
 * @param     None
 *
 * @retval    None
 */
static void DMA_Init(void)
{
    /* DMA Configure */
    DMA_Config_T dmaConfig;

    /* Enable DMA clock */
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);

    /* Set Peripheral Address */
    dmaConfig.peripheralAddress = ADC_DR_ADDR;
    /* Set memory Address */
    dmaConfig.memoryAddress = (uint32_t)&adcData;
    /* read from peripheral */
    dmaConfig.direction     = DMA_DIR_PERIPHERAL;
    /* size of buffer*/
    dmaConfig.bufferSize    = ADC_CH_SIZE;
    /* Disable Peripheral Address increase */
    dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
    /* Enable Memory Address increase */
    dmaConfig.memoryInc     = DMA_MEMORY_INC_ENABLE;
    
    /* Set peripheral Data Size */
    dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_HALFWORD;
    /* set memory Data Size */
    dmaConfig.memoryDataSize     = DMA_MEMORY_DATASIZE_HALFWORD;
    
    /* Reset Circular Mode */
    dmaConfig.circular       = DMA_CIRCULAR_ENABLE;
    /* Disable M2M */
    dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
    /* set priority */
    dmaConfig.priority       = DMA_PRIORITY_LEVEL_HIGHT;

    DMA_Config(DMA1_CHANNEL_1, &dmaConfig);

    DMA_Enable(DMA1_CHANNEL_1);
}

// 多路ADC检测，用于检测电池电压
void bsp_multi_adc_init(void)
{
    GPIO_Config_T           gpioConfig;
    ADC_Config_T            adcConfig;

    /* Enable GPIOA clock */
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOC);
    
    /* ADC channel 0 configuration */
    GPIO_ConfigStructInit(&gpioConfig);
    gpioConfig.mode    = GPIO_MODE_AN;
    gpioConfig.pupd    = GPIO_PUPD_NO;
    gpioConfig.pin     = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 |
                         GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | 
                         GPIO_PIN_7;
    GPIO_Config(GPIOA, &gpioConfig);
    
    gpioConfig.pin     = GPIO_PIN_4 | GPIO_PIN_5;
    GPIO_Config(GPIOC, &gpioConfig);
    
    gpioConfig.pin     = GPIO_PIN_0;
    GPIO_Config(GPIOB, &gpioConfig);

    /* Enable ADC clock */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);

    /* ADC configuration */
    ADC_Reset();

    ADC_ConfigStructInit(&adcConfig);
    /* Set resolution*/
    adcConfig.resolution            = ADC_RESOLUTION_12B;
    /* Set scanDir*/
    adcConfig.scanDir               = ADC_SCAN_DIR_UPWARD;
    /* Set convMode continous*/
    adcConfig.convMode              = ADC_CONVERSION_CONTINUOUS;
    /* Set dataAlign*/
    adcConfig.dataAlign             = ADC_DATA_ALIGN_RIGHT;
    /* Set extTrigEdge*/
    adcConfig.extTrigEdge           = ADC_EXT_TRIG_EDGE_NONE;
    /* Set extTrigConv*/
    adcConfig.extTrigConv           = ADC_EXT_TRIG_CONV_TRG0;
    ADC_Config(&adcConfig);

    /* ADC channel Convert configuration */
    ADC_ConfigChannel(ADC_CHANNEL_0, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_1, ADC_SAMPLE_TIME_239_5);
//    ADC_ConfigChannel(ADC_CHANNEL_2, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_3, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_4, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_5, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_6, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_7, ADC_SAMPLE_TIME_239_5);
    
    ADC_ConfigChannel(ADC_CHANNEL_14, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_15, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_8, ADC_SAMPLE_TIME_239_5);
    
    /* Config DMA*/
    DMA_Init();

    /* Calibration */
    ADC_ReadCalibrationFactor();

    /* Enable ADC DMA*/
    ADC_EnableDMA();
    ADC_DMARequestMode(ADC_DMA_MODE_CIRCULAR);
    /* Enable ADC */
    ADC_Enable();
    
    
    ADC_StartConversion();
}


/*!
 * @brief     ADC multi channel polling
 *
 * @param     None
 *
 * @retval    None
 */
void ADC_MultiChannelPolling(void)
{
    float voltage;
    uint8_t index;

    for (index = 0; index < ADC_CH_SIZE; index++)
    {
        voltage = (adcData[index] * 3300.0) / 4095.0;
        
        if (voltage)
        {;}
    }
}


#define USB_0V     1800  // 没插入电源的最大ADC值
#define USB_5V     2500  // 插入5V电源之后的最大ADC值 1.6v  
#define USB_9V     4096  // 插入9V电源之后的最大ADC值 2.8v
#define USB_ADC_BUF_SIZE  12
uint16_t _usb_adc_value; 
uint8_t _usb_adc_index;
uint16_t _usb_adc_temp[USB_ADC_BUF_SIZE]; 

usb_power_status_e check_usb_0v_5v_9v(void)
{
    uint16_t adc, i;
    usb_power_status_e  state = USB_PWR_0V;
    uint32_t sum = 0;

    if (_usb_adc_index < USB_ADC_BUF_SIZE)
    {
        _usb_adc_temp[_usb_adc_index] = adcData[2];

        _usb_adc_index++;
    }
    else
    {

        // 排序 
        quickSort(&_usb_adc_temp[0], 0, (USB_ADC_BUF_SIZE - 1));
        
        /* 计算总和 */
        for (i = 4; i < (USB_ADC_BUF_SIZE - 4); i++)
        {
            sum += _usb_adc_temp[i];
        }
        
        
        /* 求平均值 */
        _usb_adc_value = sum / (USB_ADC_BUF_SIZE - 8);
        
        _usb_adc_index = 0;
    }

    adc = _usb_adc_value;

    if(adc < USB_0V)
    {
        state = USB_PWR_0V;
    }
    else if(adc < USB_5V)
    {
        state = USB_PWR_5V;
    }
    else
    {
        state = USB_PWR_9V;
    }

    return state;
}

#define NTC_ADC_BUF_SIZE  20
uint16_t _ntc_adc_value; 
uint8_t  _ntc_adc_index;
uint16_t _ntc_adc_temp[NTC_ADC_BUF_SIZE]; 
uint16_t get_ntc_adc_value(void)
{
    uint32_t i, sum = 0;

    if (_ntc_adc_index < NTC_ADC_BUF_SIZE)
    {
        _ntc_adc_temp[_ntc_adc_index] = adcData[8];

        _ntc_adc_index++;
    }
    else
    {
        // 排序 
        quickSort(&_ntc_adc_temp[0], 0, (NTC_ADC_BUF_SIZE - 1));
        
        /* 计算总和 */
        for (i = 4; i < (NTC_ADC_BUF_SIZE - 4); i++)
        {
            sum += _ntc_adc_temp[i];
        }

        /* 求平均值 */
        _ntc_adc_value = sum / (NTC_ADC_BUF_SIZE - 8);

        _ntc_adc_index = 0;
    }
    
    return _ntc_adc_value;
}

#define BAT_CHANNEL_MAX   8
#define BAT_ADC_BUF_SIZE  20
uint8_t  _bat_buf_index;
uint16_t _bat_adc_temp[BAT_CHANNEL_MAX][BAT_ADC_BUF_SIZE];


// BAT1_ADC    PA0  ADC_IN0   √  adcData[0]  0
// BAT2_ADC    PA1  ADC_IN1   √  adcData[1]  1
// BAT3_ADC    PA4  ADC_IN4   √  adcData[3]  2
// BAT4_ADC    PA5  ADC_IN5   √  adcData[4]  3
// BAT5_ADC    PA6  ADC_IN6   √  adcData[5]  4
// BAT6_ADC    PA7  ADC_IN7   √  adcData[6]  5
// BAT7_ADC    PC5  ADC_IN15  √  adcData[9]  6
// BAT8_ADC    PB0  ADC_IN8   √  adcData[7]  7
void bat_adc_update(void)
{
    uint16_t ch;

    for (ch = 0; ch < BAT_CHANNEL_MAX; ch++)
    {
        if (ch <= 1)
        {
            _bat_adc_temp[ch][_bat_buf_index] = adcData[ch];
        }
        else if (ch <= 5)
        {
            _bat_adc_temp[ch][_bat_buf_index] = adcData[ch + 1];
        } 
        else if (ch == 6)
        {
            _bat_adc_temp[ch][_bat_buf_index] = adcData[9];
        }
        else if (ch == 7)
        {
            _bat_adc_temp[ch][_bat_buf_index] = adcData[7];
        }
    }

    if (_bat_buf_index < (BAT_ADC_BUF_SIZE - 1))
    {
        _bat_buf_index++;
    }
    else
    {
        _bat_buf_index = 0;
    }
}

uint16_t bat_adc_value(uint8_t ch)
{
    uint8_t buf_idx;
    uint16_t value = 0;
    uint32_t sum = 0;

    if (ch < BAT_CHANNEL_MAX)
    {
        // 排序
        quickSort(&_bat_adc_temp[ch][0], 0, (BAT_ADC_BUF_SIZE - 1));
        
        // 求和
        for (buf_idx = 4; buf_idx < BAT_ADC_BUF_SIZE - 4; buf_idx++)
        {
            sum += _bat_adc_temp[ch][buf_idx];
        }

        value = sum / (BAT_ADC_BUF_SIZE - 8);
    }

    return value;
}

/*
return : 0, 0 < temp < 45 ℃
         1, else
*/
uint8_t check_ntc_err_state(void)
{
    uint8_t state = 0;
    uint16_t value_temp, Vadc;
    
    value_temp = get_ntc_adc_value();
    Vadc =(uint16_t)(332 * value_temp /4095);
    
//    DEBUG_OUT("ntc ：value_temp = %d, Vadc = %d\r\n", value_temp, Vadc);
    
    if((Vadc > 55) && (Vadc < 260))
    {
        state = 0 ;
    }
    else
    {
        state = 1 ;
    }

    return state;
}

